use std::borrow::Borrow;

use wither::bson::oid::ObjectId;

use crate::models::{
    blacklist::BlacklistContent,
    user::{NormalUserModel, UserModel, UserRole},
};

pub fn check_user_has_permission<'d, C: Into<Option<String>>, U: Into<&'d UserModel>>(
    user: U,
    club_id: C,
    permission: u8,
) -> bool {
    if permission == 0 {
        return true;
    }
    let user: &UserModel = user.into();
    let club_id: Option<String> = club_id.into();
    let up = user
        .actors
        .iter()
        .filter_map(|f| match &club_id {
            Some(club_id) => match f.club_id {
                Some(oid) => {
                    if oid.to_string().as_str() == club_id.as_str() {
                        Some(f.role as u8)
                    } else {
                        None
                    }
                }
                None => Some(f.role as u8),
            },
            None => {
                if f.club_id.is_none() {
                    Some(f.role as u8)
                } else {
                    None
                }
            }
        })
        .reduce(|a, b| a | b)
        .unwrap_or(UserRole::Guest as u8);
    up & permission != 0 || up & UserRole::SuperAdmin as u8 != 0
}

pub fn check_user_has_permission_with_object_id<
    C: Into<Option<ObjectId>>,
    U: Borrow<NormalUserModel>,
    S: Into<u8>,
>(
    user: U,
    club_id: C,
    permission: S,
) -> bool {
    let user: &NormalUserModel = user.borrow();
    let club_id: Option<ObjectId> = club_id.into();
    let permission: u8 = permission.into();
    if permission == 0 {
        return true;
    }
    let up = user
        .actors
        .iter()
        .filter_map(|f| match club_id.as_ref() {
            Some(club_id) => match &f.club_id {
                Some(oid) => {
                    if club_id == oid {
                        Some(f.role as u8)
                    } else {
                        None
                    }
                }
                None => Some(f.role as u8),
            },
            None => {
                if f.club_id.is_none() {
                    Some(f.role as u8)
                } else {
                    None
                }
            }
        })
        .reduce(|a, b| a | b)
        .unwrap_or(UserRole::Guest as u8);
    up & permission != 0 || up & (UserRole::SuperAdmin as u8) != 0
}
/// ## 检查用户是否具有某个文章板块的权限
pub fn check_user_has_section_permission<
    U: Borrow<NormalUserModel>,
    S: Into<Option<ObjectId>>,
    P: Into<u8>,
>(
    user: U,
    section_id: S,
    permission: P,
) -> bool {
    let permission: u8 = permission.into();
    let section_id: Option<ObjectId> = section_id.into();
    if permission == UserRole::Guest as u8 {
        return true;
    }
    let user_borrow: &NormalUserModel = user.borrow();
    let up = user_borrow
        .actors
        .iter()
        .filter_map(|f| match (&section_id, f.article_section_id.as_ref()) {
            (Some(a), Some(b)) if a == b => Some(f.role),
            (Some(_), None) => Some(f.role),
            (None, None) => Some(f.role),
            _ => None,
        })
        .reduce(|a, b| a | b)
        .unwrap_or(UserRole::Guest as u8);
    up & permission != 0 || up & (UserRole::SuperAdmin as u8) != 0
}

/// ## 检查用户是否拥有编辑黑名单的权限
pub fn check_user_has_blacklist_edit_prommission<
    U: Borrow<NormalUserModel>,
    C: Borrow<BlacklistContent>,
>(
    user: U,
    content: C,
) -> bool {
    let content: &BlacklistContent = content.borrow();
    match content {
        BlacklistContent::Application { club_id } => {
            check_user_has_permission_with_object_id(user, *club_id, UserRole::LeaderOrAdmin)
        }
        BlacklistContent::Article { section_id } => {
            check_user_has_section_permission(user, *section_id, UserRole::LeaderOrAdmin)
        }
        _ => false,
    }
}
mod promission_check {

    pub async fn check_user_has_role() -> bool {
        todo!()
    }
    pub async fn check_user_has_form_read_promission() -> bool {
        todo!()
    }
    pub async fn check_user_has_apply_form_promission() -> bool {
        todo!()
    }
    pub async fn check_user_has_entiry_club_promission() -> bool {
        todo!()
    }
    pub async fn check_user_has_change_club_info_promission() -> bool {
        todo!()
    }
    pub async fn check_user_has_change_apply_promission() -> bool {
        todo!()
    }
    pub async fn check_user_has_change_apply_status_promission() -> bool {
        todo!()
    }
}
pub use promission_check::*;
